﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Net;
using System.Runtime.InteropServices;
using System.Collections;
using System.Web;
using System.Threading;

namespace AProxy
{
    public class ProxyGrabber
    {
        public Form1 GUI;
        private int FPLPages = -1;
        private int current = 0;
        private int getCase = 0;
        public volatile Queue<AProxy> list = new Queue<AProxy>();
        private String fileLoc = "";
        private int proxyCount = 0;
        public Thread[] threads = new Thread[5];
        public volatile StreamWriter sw;
        private char[] MPLPagePhrase = { 'p', 'a', 'g', 'e', '=' };
        private char[] MPLBreakPhrase = { '<', 'b', 'r', };
        private char[] MPLDecodePhrase = { 'I', 'P', 'D', 'e', 'c', 'o', 'd', 'e', '(', '"' };
        private char[] MPLPortPhrase = { 'r', '"', '>' };
        private char[] VPNGDecodePhrases = { '"', 't', 'r', '_', 's', 't', 'y', 'l', 'e' };
        private char[] VPNGBreakPhrase = { '<', 't', 'd', '>' };
        private char[] VPNGPagePhrase = { 'p', 'r', 'o', 'x', 'y', 'l', 'i', 's', 't', '.', 'p', 'h', 'p', '?', 'f', 'r', 'o', 'm', '=' };
        private char[] VPNGPageBreakPhrase = { 'n', 'e', 'x', 't' };
        public ProxyGrabber()
        {
            GUI = new Form1();
            GUI.getWebBrowser().DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
            // httpRequest("http://www.vpngeeks.com/proxylist.php?country=0&port=&speed%5B%5D=2&speed%5B%5D=3&anon%5B%5D=1&anon%5B%5D=2&anon%5B%5D=3&type%5B%5D=1&type%5B%5D=2&conn%5B%5D=2&conn%5B%5D=3&sort=1&order=1&rows=50&search=Find+Proxy");
        }

        public String httpRequest(String url)
        {
            WebRequest request = WebRequest.Create(url);

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            Stream dataStream = response.GetResponseStream();

            StreamReader reader = new StreamReader(dataStream);

            string responseFromServer = reader.ReadToEnd();

            //  Console.WriteLine(responseFromServer);

            reader.Close();

            dataStream.Close();

            response.Close();

            return responseFromServer;
        }

        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            GUI.updateUrl();
            if (GUI.getWebBrowser().ReadyState != WebBrowserReadyState.Complete)
            {
                return;
            }
            if (fileLoc.Equals(""))
            {
                SaveFileDialog saveFileDialog1 = new SaveFileDialog();
                saveFileDialog1.Title = "Save the list";
                saveFileDialog1.FileName = "Proxy.txt";
                saveFileDialog1.ShowDialog();
                fileLoc = saveFileDialog1.FileName;
                sw = new StreamWriter(fileLoc, true);
                for (int i = 0; i < threads.Length; i++)
                {
                    Worker worker = new Worker(list, sw);
                    threads[i] = new Thread(worker.DoWork);
                    threads[i].Start();
                }
            }
            if (GUI.getWebBrowser().DocumentText.Contains("This program cannot display the webpage"))
            {
                GUI.getWebBrowser().Navigate(e.Url);
            }
            else
            {
                if (FPLPages == -1)
                {
                    setPageNumber(getCase);
                }
                char[] text = GUI.getWebBrowser().DocumentText.ToCharArray();
                if (getCase == 0)
                {
                    getFPLProxyEfficent(text);

                }
                else if (getCase == 1)
                {
                    Console.WriteLine(current + "/" + FPLPages);
                    getVPNGeekEfficently(text);
                }
                else
                {
                    System.Environment.Exit(0);
                }
            }
            return;
        }

        private int setPageNumber(int pos)
        {
            switch (pos)
            {
                case 0:
                    FPLPages = getPages(GUI.getWebBrowser().DocumentText.ToCharArray(), MPLPagePhrase, MPLBreakPhrase);
                    break;
                case 1:
                    FPLPages = (int)((getPages(GUI.getWebBrowser().DocumentText.ToCharArray(), VPNGPagePhrase, VPNGPageBreakPhrase) / 200));
                    break;
            }
            return -1;
        }

        private int getWebPage(String s)
        {
            if (s.Contains("http://freeproxylists.net"))
            {
                return 0;
            }
            else if (s.Contains("http://www.vpngeeks.com/"))
            {
                return 1;
            }
            return -1;
        }

        private Boolean hasPort(String ip)
        {
            return (ip.Contains(":") && ip.Split(':')[1].Length > 0);
        }

        private String urlDecoder(String encoded)
        {
            return HttpUtility.UrlDecode(encoded);
        }

        //-1 Not found
        private int findLocation(char[] text, int startpos, char[] target)
        {
            for (int i = startpos; i < text.Length; i++)
            {
                String phrase = "";
                for (int j = 0; j < target.Length; j++)
                {
                    if (target[j].Equals(text[i]))
                    {
                        phrase = phrase + text[i];
                        if (j + 1 == target.Length)
                        {
                            return i;
                        }
                        else
                        {
                            i++;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }
            return -1;
        }

        public void getVPNGeekEfficently(Char[] line)
        {//VPNGDecodePhrases
            int i = 0;
            Console.WriteLine("Starting");
            while ((i = findLocation(line, i, VPNGDecodePhrases)) != -1)
            {
                i = i + 8;
                String code = "";
                String port = ""; ;
                while (char.IsDigit(line[i]) || line[i] == '.')
                {
                    code = code + line[i];
                    i++;
                }

                i = findLocation(line, i, VPNGBreakPhrase);
                i++;

                while (char.IsDigit(line[i]))
                {
                    port = port + line[i];
                    i++;
                }
                list.Enqueue(new AProxy(code, int.Parse(port)));
                proxyCount++;
                GUI.updateProxy(proxyCount);

            }
            if (current == FPLPages)
            {
                FPLPages = -1;
                getCase++;
            }
            else
            {
                current++;
                Console.WriteLine(FPLPages);
                GUI.getWebBrowser().Navigate("http://www.vpngeeks.com/proxylist.php?from=" + ((current * 200) + 1) + "&country=0&port=&speed%5B%5D=2&speed%5B%5D=3&anon%5B%5D=1&anon%5B%5D=2&anon%5B%5D=3&type%5B%5D=1&type%5B%5D=2&conn%5B%5D=2&conn%5B%5D=3&sort=1&order=1&rows=200&search=Find+Proxy#pagination");
            }
        }

        public void getFPLProxyEfficent(char[] line)
        {
            int i = 0;
            while ((i = findLocation(line, i, MPLDecodePhrase)) != -1)
            {
                i++;
                String code = "";
                String port = "";
                i++;
                while (!line[i].Equals('<'))
                {
                    code = code + line[i];
                    i++;
                }
                code = urlDecoder(code);
                code = parseStringToIP(code);
                while ((i = findLocation(line, i, MPLPortPhrase)) != -1)
                {
                    i++;
                    while (char.IsDigit(line[i]))
                    {
                        port = port + line[i];
                        i++;
                    }
                    list.Enqueue(new AProxy(code, int.Parse(port)));
                    proxyCount++;
                    GUI.updateProxy(proxyCount);
                    break;
                }

            }
            if (current == FPLPages)
            {
                current = 0;
                GUI.getWebBrowser().Navigate("http://www.vpngeeks.com/proxylist.php?from=1&country=0&port=&speed%5B%5D=2&speed%5B%5D=3&anon%5B%5D=1&anon%5B%5D=2&anon%5B%5D=3&type%5B%5D=1&type%5B%5D=2&conn%5B%5D=2&conn%5B%5D=3&sort=1&order=1&rows=200&search=Find+Proxy#pagination");
                getCase++;
                FPLPages = -1;
            }
            else
            {
                current++;
                GUI.getWebBrowser().Navigate("www.freeproxylists.net/?page=" + (current + 1));
            }
        }

        public int getPages(char[] line, char[] phrase, char[] breakPhrase)
        {

            int pageNumber = -1;
            Boolean start = false;
            for (int i = 0; i < line.Length; i++)
            {
                for (int j = 0; j < phrase.Length; j++)
                {

                    if (phrase[j].Equals(line[i]))
                    {

                        if (j + 1 == phrase.Length)
                        {
                            start = true;
                            String value = "";
                            i++;
                            while (char.IsDigit(line[i]))
                            {
                                value = value + line[i];
                                i++;
                            }
                            if (value.Length == 0)
                            {
                                break;
                            }
                            int num = int.Parse(value);
                            if (pageNumber < num)
                            {
                                pageNumber = num;
                            }
                            break;
                        }
                        else
                        {
                            i++;
                        }
                    }
                    else if (start)
                    {
                        for (int k = 0; k < breakPhrase.Length; k++)
                        {
                            if (breakPhrase[k].Equals(line[i]))
                            {
                                if (k + 1 == breakPhrase.Length)
                                {
                                    return pageNumber;
                                }
                                i++;
                            }
                            else
                            {
                                goto outerLoop;
                            }
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            outerLoop: ;

            }

            return pageNumber;
        }

        public String parseStringToIP(String s)
        {
            char[] characters = s.ToCharArray();
            for (int i = 0; i < characters.Length; i++)
            {
                char c = characters[i];
                String last = null;
                String ip = "";
                int section = 0;
                int pos = 0;
                while (Char.IsDigit(c) || c == '.')
                {
                    if (c == '.')
                    {
                        if (pos == 0 || pos > 3 || section >= 4)
                        {
                            break;
                        }


                        ip += c;
                        section++;
                        pos = 0;
                        last = c + "";
                    }
                    else
                    {
                        if (pos == 3)
                        {
                            break;
                        }
                        pos++;
                        ip += c;
                        last = c + "";
                    }
                    i++;
                    c = characters[i];
                }
                if ((section == 3 && pos > 0))
                {
                    return ip;
                }
            }
            return null;
        }
    

    
    }

    public class Worker
    {

        public volatile Queue<AProxy> list = new Queue<AProxy>();

        public volatile Boolean _shouldStop = false;
        public volatile StreamWriter sw;

        public Worker(Queue<AProxy> list, StreamWriter sw)
        {
            this.list = list;
            this.sw = sw;
        }

        public void checkPort(){
            if (list.Count != 0)
            {

                try
                {
                    AProxy temp = list.Dequeue();
                    WebRequest req = WebRequest.Create("http://google.com");
                    req.Proxy = new WebProxy(temp.getIP(), temp.getPort());
                    req.Timeout = 10000;
                    req.GetResponse();
                    lock (sw)
                    {
                        Console.WriteLine(temp.getIP() + ":" + temp.getPort());
                        sw.WriteLine(temp.getIP() + ":" + temp.getPort());
                        sw.Flush();

                    }
                }
                catch
                {

                }
            }
            else
            {
                Thread.Sleep(1000);
            }
        }

        public void DoWork()
        {
            while (!_shouldStop)
            {
               checkPort();

            }
            Console.WriteLine("worker thread: terminating gracefully.");
        }
        public void RequestStop()
        {
            _shouldStop = true;
        }
    }
}
